import M_Evaluate
# 输入：种群中的个体集合  不是整个种群
# 输出：快速非支配排序结果[[,..,],...,[,...,]]


# 判断个体1是否支配个体2
def Is_Dominate(Idv1, Idv2):
    print("模块：Fast_Sort\t方法：Is_Dominate(Idv1, Idv2):")
    # 目标空间维度
    Objective_Dim = len(Idv1.Adaptability)
    # 两个个体的目标值
    Objective1 = []
    Objective2 = []

    for i in range(Objective_Dim):
        Objective1.append(Idv1.Adaptability[i])
        Objective2.append(Idv2.Adaptability[i])

    # 判断向量
    Flag = [9999] * Objective_Dim

    for i in range(Objective_Dim):
        if Objective1[i] < Objective2[i]:
            Flag[i] = -1    # 目标值小
        elif Objective1[i] == Objective2[i]:
            Flag[i] = 0     # 目标值相等

    # 判断支配的条件如下:
    # 不能全部相等 ---> 不能全0
    # 不能存在个体2目标值比个体1好的   ---> 不能有9999
    return True if sum(Flag) < 0  else False


# 计算Pareto前沿面 服务于快速非支配排序
# 输入：个体集合
# 输出：Pareto前沿面
def Get_First_Dominate(Population_Pub):
    print("模块：Fast_Sort\t方法：Get_First_Dominate(Population_Pub):")
    Pop_Size = len(Population_Pub)       # 个体集合的数量
    Np = [0] * Pop_Size                  # 支配当前个体的 个体数量  初始化为0
    Sp = [[] for _ in range(Pop_Size)]   # 被当前个体支配的 个体集  初始化为[]
    First_Pareto = []                    # Pareto 前沿面
    for i in range(Pop_Size):
        for j in range(i+1,Pop_Size):
                # print(Population_Pub[i],Population_Pub[j])                
                if Is_Dominate(Population_Pub[i], Population_Pub[j]):    # 个体i支配个体j
                    Np[j] += 1       # 支配个体j的个体数量加1
                    Sp[i].append(j)  # 将个体j加入个体i的支配集                
                elif Is_Dominate(Population_Pub[j], Population_Pub[i]):  # 个体j支配个体i
                    Np[i] += 1       # 支配个体i的个体数量加1
                    Sp[j].append(i)  # 将个体i加入个体j的支配集
        # 如果没有个体支配个体i，则此个体是Parato解
        if Np[i] == 0:
            First_Pareto.append(i)
    return Np,Sp,First_Pareto               


# 快速非支配排序
# 输入：个体集合  并非整个种群
# 输出：非支配排序结果
def Fast_Nodominate_Sort(Population_Member):
    print("模块：Fast_Sort\t方法：Fast_Nodominate_Sort(Population_Member):")
    # 第一个Parato前沿面
    Np,Sp,First_Parato = Get_First_Dominate(Population_Member)
    Nodominate_Sort = []                      # 非支配排序每个等级

    while(len(First_Parato) != 0):
        Nodominate_Sort.append(First_Parato)  # 加入第一个前沿面
        Temp = []                             # 加入后续Pareto面
        for j in First_Parato:
            p = Sp[j]                         # 找到pareto前沿面个体的支配集  
            for q in p:                       # 将支配集中每个个体都得 支配数减少1
                Np[q] -= 1   
                if Np[q] == 0:                # 找到下一层前沿面  当前前沿面个体遍历完成 进行下一层
                    Temp.append(q)
        First_Parato = Temp
    return Nodominate_Sort


# 更改的拥挤度算子
# 方式：根据OS染色体和MS染色体 在种群中出现次数进行计算
# 输入：某一层Pareto面 和 个体集合
# 输出：此层的拥挤度距离
def Modified_Crowding_Distance(Pareto,Population_Member):
    print("模块：Fast_Sort\t方法：Modified_Crowding_Distance(Pareto,Population_Member): ")
    Pareto_Size = len(Pareto)
    Pop_Size = len(Population_Member)                 
    Di = []     # 这层Pareto 个体的拥挤度距离
    for m in range(Pareto_Size):
        OS_Value = 1
        MS_Value = 1
        for n in range(Pop_Size):
            if Pareto[m] != n:
                if Population_Member[Pareto[m]].Job_Chromosome.tolist() == Population_Member[n].Job_Chromosome.tolist():
                    OS_Value += 1
                if Population_Member[Pareto[m]].Machine_Chromosome.tolist() == Population_Member[n].Machine_Chromosome.tolist():
                    MS_Value += 1

        di =  (Pop_Size - (OS_Value + MS_Value)/2) / Pop_Size
        Di.append(di)
    return Di    


# 拥挤度算子
# 方式：前后个体的超体积
# 输入：某一层Pareto面 和 个体集合
# 输出：此层的拥挤度距离  [拥挤度,个体下标]  排好序
def Crowd_Distance(Population_Member,Pareto):
    print("模块：Fast_Sort\t方法：Crowd_Distance(Population_Member,Pareto):")
    Pareto_Num = len(Pareto)    # Pareto 个体数量
    Object_Value = []           # 获得pareto面上的个体的目标值
    for m in Pareto:
        Temp = []
        for n in range(len(Population_Member[0].Adaptability)):
            Temp.append(Population_Member[m].Adaptability[n])
        Object_Value.append(Temp)   

    # 归一化处理
    Normal_Population_Objection = M_Evaluate.Normal_Objective(Object_Value)

    # 计算拥挤度 [拥挤度,下标]  
    for i in range(Pareto_Num):
        Normal_Population_Objection[i].append(Pareto[i])

    # 二维的话 sorted 排序就行 因为必定是以一维增加  另外一维目标减少的
    # 高维情况的话  必须 找到在每一维的左右个体的距离 然后乘起来计算超体积

    Distance = []
    Normal_Population_Objection = sorted(Normal_Population_Objection)

    for i in range(Pareto_Num):
        Temp1 = []
        if Normal_Population_Objection[i][0] == 0 and Normal_Population_Objection[i][1] == 1 or Normal_Population_Objection[i][0] == 1 and Normal_Population_Objection[i][1] == 0:
            Temp1.append(9999)                
        else:
            distance_value = 0
            distance_value = (Normal_Population_Objection[i+1][0]-Normal_Population_Objection[i-1][0]) * (Normal_Population_Objection[i-1][1]-Normal_Population_Objection[i+1][1])
            Temp1.append(distance_value)
        Temp1.append(Normal_Population_Objection[i][2])
        Distance.append(Temp1)

    # 拥挤度排序  挑大的
    Distance = sorted(Distance)
    return Distance




